<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
<script src="https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/picture/pika.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/picture/pika.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="baidu-site-verification" content="code-LqqDM3vffE">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">


  <script>
  (function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/2efd5eff.js","daovoice")
  daovoice('init', {
    app_id: "2efd5eff"
  });
  daovoice('update');
  </script>


<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"notspr.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":true,"color":"#ff7600","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":false,"async":true,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="全栈 | 硬件 | 篮球 | 游戏">
<meta property="og:type" content="website">
<meta property="og:title" content="Sapphire">
<meta property="og:url" content="https://notspr.com/page/4/index.html">
<meta property="og:site_name" content="Sapphire">
<meta property="og:description" content="全栈 | 硬件 | 篮球 | 游戏">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="Ryan Shu">
<meta property="article:tag" content="博客">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://notspr.com/page/4/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>Sapphire - 興趣使然的博客</title>
  


  <script data-pjax>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?2907d577c8c6c2f7fe3843736d24280d";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

  <!--pjax：防止跳转页面音乐暂停-->
  <script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.js"></script>
<link rel="alternate" href="/atom.xml" title="Sapphire" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Sapphire</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">興趣使然的博客</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/aboutme/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签<span class="badge">82</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类<span class="badge">34</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档<span class="badge">40</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="reading-progress-bar"></div>
  <a role="button" class="book-mark-link book-mark-link-fixed"></a>

  <a href="https://github.com/sususama5555" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2020/04/03/go-basis-exercise-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2020/04/03/go-basis-exercise-1/" class="post-title-link" itemprop="url">Go语言基础练习一</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-04-03 00:04:00" itemprop="dateCreated datePublished" datetime="2020-04-03T00:04:00+08:00">2020-04-03</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Golang/" itemprop="url" rel="index"><span itemprop="name">Golang</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Golang/%E5%9F%BA%E7%A1%80%E7%BB%83%E4%B9%A0/" itemprop="url" rel="index"><span itemprop="name">基础练习</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>1.7k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>2 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <blockquote>
<h2 id="Go语言基础练习一"><a href="#Go语言基础练习一" class="headerlink" title="Go语言基础练习一"></a>Go语言基础练习一</h2></blockquote>
<p>以下是笔者学习Go语言基础的代码随笔，主要为数据类型与变量申明。</p>
<h3 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h3><p>在 Go 编程语言中，数据类型用于声明函数和变量。</p>
<p>Go 语言按类别有以下几种数据类型：</p>
<table>
<thead>
<tr>
<th align="left">序号</th>
<th align="left">类型和描述</th>
</tr>
</thead>
<tbody><tr>
<td align="left">1</td>
<td align="left"><strong>布尔型</strong> 布尔型的值只可以是常量 true 或者 false。一个简单的例子：var b bool = true。</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left"><strong>数字类型</strong> 整型 int 和浮点型 float32、float64，Go 语言支持整型和浮点型数字，并且支持复数，其中位的运算采用补码。</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left"><strong>字符串类型:</strong> 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。</td>
</tr>
<tr>
<td align="left">4</td>
<td align="left"><strong>派生类型:</strong> 包括：(a) 指针类型（Pointer）(b) 数组类型(c) 结构化类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型（interface）(h) Map 类型</td>
</tr>
</tbody></table>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2020/04/03/go-basis-exercise-1/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2020/03/21/django-orm/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2020/03/21/django-orm/" class="post-title-link" itemprop="url">Django之ORM操作</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-03-21 03:07:42" itemprop="dateCreated datePublished" datetime="2020-03-21T03:07:42+08:00">2020-03-21</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Django/" itemprop="url" rel="index"><span itemprop="name">Django</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Django/ORM/" itemprop="url" rel="index"><span itemprop="name">ORM</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>3.1k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>3 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <blockquote>
<h1 id="Django-ORM"><a href="#Django-ORM" class="headerlink" title="Django ORM"></a>Django ORM</h1></blockquote>
<p>Django 模型使用自带的 ORM。</p>
<p><kbd>对象关系映射</kbd>（Object Relational Mapping，简称 ORM ）用于实现面向对象编程语言里不同类型系统的数据之间的转换。</p>
<p>ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。</p>
<p>ORM 是通过使用描述对象和数据库之间的映射的元数据，将程序中的对象自动持久化到数据库中。</p>
<img data-src="/2020/03/21/django-orm/django-orm1.png" class>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2020/03/21/django-orm/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2020/03/18/python-thread-process/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2020/03/18/python-thread-process/" class="post-title-link" itemprop="url">Python之多线程与多进程</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-03-18 23:31:07" itemprop="dateCreated datePublished" datetime="2020-03-18T23:31:07+08:00">2020-03-18</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Python/" itemprop="url" rel="index"><span itemprop="name">Python</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Python/%E5%A4%9A%E4%BB%BB%E5%8A%A1/" itemprop="url" rel="index"><span itemprop="name">多任务</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>8.1k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>7 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <blockquote>
<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3></blockquote>
<p>现代操作系统比如Mac OS X，UNIX，Linux，Windows等，都是支持“多任务”的操作系统，操作系统可以同时运行多个任务。</p>
<p>对于操作系统来说，一个任务就是一个进程（Process），比如打开一个浏览器就是启动一个浏览器进程，打开一个记事本就启动了一个记事本进程，打开两个记事本就启动了两个记事本进程，打开一个Word就启动了一个Word进程。</p>
<p>有些进程还不止同时干一件事，比如Word，它可以同时进行打字、拼写检查、打印等事情。在一个进程内部，要同时干多件事，就需要同时运行多个“子任务”，我们把进程内的这些“子任务”称为线程（Thread）。</p>
<p>多任务的实现有3种方式：</p>
<ul>
<li>多进程模式；</li>
<li>多线程模式；</li>
<li>多进程 + 多线程模式。</li>
</ul>
<p>Python既支持多进程，又支持多线程，线程是最小的执行单元，而进程由至少一个线程组成。如何调度进程和线程，完全由操作系统决定，程序自己不能决定什么时候执行，执行多长时间。</p>
<p>多进程和多线程的程序涉及到同步、数据共享的问题，编写起来更复杂。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2020/03/18/python-thread-process/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2020/02/26/pearson-formula/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2020/02/26/pearson-formula/" class="post-title-link" itemprop="url">pearson相关系数</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-02-26 16:09:38" itemprop="dateCreated datePublished" datetime="2020-02-26T16:09:38+08:00">2020-02-26</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" itemprop="url" rel="index"><span itemprop="name">学习笔记</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>1.1k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p><strong>pearson相关系数</strong></p>
<p><img data-src="/picture/pearson%E5%85%AC%E5%BC%8F.png" alt="avatar"></p>
<p>公式定义为： 两个连续变量(X,Y)的pearson相关性系数(Px,y)等于它们之间的协方差cov(X,Y)除以它们各自标准差的乘积(σX,σY)。系数的取值总是在-1.0到1.0之间，接近0的变量被成为无相关性，接近1或者-1被称为具有强相关性。</p>
<p>简单来说，它用来衡量两个数据集合是否在一条线上面，是否有相关性，这在数据分析中是很有效的。</p>
<p>用python3实现：</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2020/02/26/pearson-formula/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/12/24/http-clan/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/12/24/http-clan/" class="post-title-link" itemprop="url">HTTP网络协议族</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-12-24 00:16:30" itemprop="dateCreated datePublished" datetime="2019-12-24T00:16:30+08:00">2019-12-24</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" itemprop="url" rel="index"><span itemprop="name">计算机网络</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/HTTP/" itemprop="url" rel="index"><span itemprop="name">HTTP</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>16k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>14 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="基础概念"><a href="#基础概念" class="headerlink" title="基础概念"></a>基础概念</h2><h3 id="请求和响应报文"><a href="#请求和响应报文" class="headerlink" title="请求和响应报文"></a>请求和响应报文</h3><p>客户端发送一个请求报文给服务器，服务器根据请求报文中的信息进行处理，并将处理结果放入响应报文中返回给客户端。</p>
<p>请求报文结构：</p>
<ul>
<li>第一行是包含了请求方法、URL、协议版本；</li>
<li>接下来的多行都是请求首部 Header，每个首部都有一个首部名称，以及对应的值。</li>
<li>一个空行用来分隔首部和内容主体 Body</li>
<li>最后是请求的内容主体</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">GET http:&#x2F;&#x2F;www.example.com&#x2F; HTTP&#x2F;1.1</span><br><span class="line">Accept: text&#x2F;html,application&#x2F;xhtml+xml,application&#x2F;xml;q&#x3D;0.9,image&#x2F;webp,image&#x2F;apng,*&#x2F;*;q&#x3D;0.8,application&#x2F;signed-exchange;v&#x3D;b3;q&#x3D;0.9</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Accept-Language: zh-CN,zh;q&#x3D;0.9,en;q&#x3D;0.8</span><br><span class="line">Cache-Control: max-age&#x3D;0</span><br><span class="line">Host: www.example.com</span><br><span class="line">If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT</span><br><span class="line">If-None-Match: &quot;3147526947+gzip&quot;</span><br><span class="line">Proxy-Connection: keep-alive</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">User-Agent: Mozilla&#x2F;5.0 xxx</span><br><span class="line"></span><br><span class="line">param1&#x3D;1&amp;param2&#x3D;2</span><br></pre></td></tr></table></figure>

<p>响应报文结构：</p>
<ul>
<li>第一行包含协议版本、状态码以及描述，最常见的是 200 OK 表示请求成功了</li>
<li>接下来多行也是首部内容</li>
<li>一个空行分隔首部和内容主体</li>
<li>最后是响应的内容主体</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">HTTP&#x2F;1.1 200 OK</span><br><span class="line">Age: 529651</span><br><span class="line">Cache-Control: max-age&#x3D;604800</span><br><span class="line">Connection: keep-alive</span><br><span class="line">Content-Encoding: gzip</span><br><span class="line">Content-Length: 648</span><br><span class="line">Content-Type: text&#x2F;html; charset&#x3D;UTF-8</span><br><span class="line">Date: Mon, 02 Nov 2020 17:53:39 GMT</span><br><span class="line">Etag: &quot;3147526947+ident+gzip&quot;</span><br><span class="line">Expires: Mon, 09 Nov 2020 17:53:39 GMT</span><br><span class="line">Keep-Alive: timeout&#x3D;4</span><br><span class="line">Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT</span><br><span class="line">Proxy-Connection: keep-alive</span><br><span class="line">Server: ECS (sjc&#x2F;16DF)</span><br><span class="line">Vary: Accept-Encoding</span><br><span class="line">X-Cache: HIT</span><br><span class="line"></span><br><span class="line">&lt;!doctype html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">    &lt;title&gt;Example Domain&lt;&#x2F;title&gt;</span><br><span class="line">	&#x2F;&#x2F; 省略... </span><br><span class="line">&lt;&#x2F;body&gt;</span><br><span class="line">&lt;&#x2F;html&gt;</span><br></pre></td></tr></table></figure>

<h3 id="URL"><a href="#URL" class="headerlink" title="URL"></a>URL</h3><p>HTTP 使用 URL（ <strong>U</strong> niform <strong>R</strong>esource <strong>L</strong>ocator，统一资源定位符）来定位资源，它是 URI（<strong>U</strong>niform <strong>R</strong>esource <strong>I</strong>dentifier，统一资源标识符）的子集，URL 在 URI 的基础上增加了定位能力。URI 除了包含 URL，还包含 URN（Uniform Resource Name，统一资源名称），它只是用来定义一个资源的名称，并不具备定位该资源的能力。例如 urn:isbn:0451450523 用来定义一个书籍名称，但是却没有表示怎么找到这本书。</p>
<p><a href="https://camo.githubusercontent.com/5be7de544b24ef21636514dd9923735c2a61c1bfc4127a69f94653c8b9b8f76c/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f38343431623263342d646361372d346436622d386566622d6632326566636361663333312e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/5be7de544b24ef21636514dd9923735c2a61c1bfc4127a69f94653c8b9b8f76c/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f38343431623263342d646361372d346436622d386566622d6632326566636361663333312e706e67" alt="img"></a></p>
<ul>
<li><a href="https://zh.wikipedia.org/wiki/统一资源标志符" target="_blank" rel="noopener">wikipedia：统一资源标志符</a></li>
<li><a href="https://en.wikipedia.org/wiki/URL" target="_blank" rel="noopener">wikipedia: URL</a></li>
<li><a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.2" target="_blank" rel="noopener">rfc2616：3.2.2 http URL</a></li>
<li><a href="https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn" target="_blank" rel="noopener">What is the difference between a URI, a URL and a URN?</a></li>
</ul>
<h2 id="HTTP-方法"><a href="#HTTP-方法" class="headerlink" title="HTTP 方法"></a>HTTP 方法</h2><p>客户端发送的 <strong>请求报文</strong> 第一行为请求行，包含了方法字段。</p>
<h3 id="GET"><a href="#GET" class="headerlink" title="GET"></a>GET</h3><blockquote>
<p>获取资源</p>
</blockquote>
<p>当前网络请求中，绝大部分使用的是 GET 方法。</p>
<h3 id="HEAD"><a href="#HEAD" class="headerlink" title="HEAD"></a>HEAD</h3><blockquote>
<p>获取报文首部</p>
</blockquote>
<p>和 GET 方法类似，但是不返回报文实体主体部分。</p>
<p>主要用于确认 URL 的有效性以及资源更新的日期时间等。</p>
<h3 id="POST"><a href="#POST" class="headerlink" title="POST"></a>POST</h3><blockquote>
<p>传输实体主体</p>
</blockquote>
<p>POST 主要用来传输数据，而 GET 主要用来获取资源。</p>
<p>更多 POST 与 GET 的比较请见第九章。</p>
<h3 id="PUT"><a href="#PUT" class="headerlink" title="PUT"></a>PUT</h3><blockquote>
<p>上传文件</p>
</blockquote>
<p>由于自身不带验证机制，任何人都可以上传文件，因此存在安全性问题，一般不使用该方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">PUT &#x2F;new.html HTTP&#x2F;1.1</span><br><span class="line">Host: example.com</span><br><span class="line">Content-type: text&#x2F;html</span><br><span class="line">Content-length: 16</span><br><span class="line"></span><br><span class="line">&lt;p&gt;New File&lt;&#x2F;p&gt;</span><br></pre></td></tr></table></figure>

<h3 id="PATCH"><a href="#PATCH" class="headerlink" title="PATCH"></a>PATCH</h3><blockquote>
<p>对资源进行部分修改</p>
</blockquote>
<p>PUT 也可以用于修改资源，但是只能完全替代原始资源，PATCH 允许部分修改。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">PATCH &#x2F;file.txt HTTP&#x2F;1.1</span><br><span class="line">Host: www.example.com</span><br><span class="line">Content-Type: application&#x2F;example</span><br><span class="line">If-Match: &quot;e0023aa4e&quot;</span><br><span class="line">Content-Length: 100</span><br><span class="line"></span><br><span class="line">[description of changes]</span><br></pre></td></tr></table></figure>

<h3 id="DELETE"><a href="#DELETE" class="headerlink" title="DELETE"></a>DELETE</h3><blockquote>
<p>删除文件</p>
</blockquote>
<p>与 PUT 功能相反，并且同样不带验证机制。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DELETE &#x2F;file.html HTTP&#x2F;1.1</span><br></pre></td></tr></table></figure>

<h3 id="OPTIONS"><a href="#OPTIONS" class="headerlink" title="OPTIONS"></a>OPTIONS</h3><blockquote>
<p>查询支持的方法</p>
</blockquote>
<p>查询指定的 URL 能够支持的方法。</p>
<p>会返回 <code>Allow: GET, POST, HEAD, OPTIONS</code> 这样的内容。</p>
<h3 id="CONNECT"><a href="#CONNECT" class="headerlink" title="CONNECT"></a>CONNECT</h3><blockquote>
<p>要求在与代理服务器通信时建立隧道</p>
</blockquote>
<p>使用 SSL（Secure Sockets Layer，安全套接层）和 TLS（Transport Layer Security，传输层安全）协议把通信内容加密后经网络隧道传输。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONNECT www.example.com:443 HTTP&#x2F;1.1</span><br></pre></td></tr></table></figure>

<p><a href="https://camo.githubusercontent.com/5b900cbd7bbb78f2ce5f4d83801041a1d59178b6c5f6078cbe435880c2320ef4/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f64633030663730652d633563382d346432302d626166312d3264373030313461393765332e6a7067" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/5b900cbd7bbb78f2ce5f4d83801041a1d59178b6c5f6078cbe435880c2320ef4/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f64633030663730652d633563382d346432302d626166312d3264373030313461393765332e6a7067" alt="img"></a></p>
<h3 id="TRACE"><a href="#TRACE" class="headerlink" title="TRACE"></a>TRACE</h3><blockquote>
<p>追踪路径</p>
</blockquote>
<p>服务器会将通信路径返回给客户端。</p>
<p>发送请求时，在 Max-Forwards 首部字段中填入数值，每经过一个服务器就会减 1，当数值为 0 时就停止传输。</p>
<p>通常不会使用 TRACE，并且它容易受到 XST 攻击（Cross-Site Tracing，跨站追踪）。</p>
<ul>
<li><a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html" target="_blank" rel="noopener">rfc2616：9 Method Definitions</a></li>
</ul>
<h2 id="HTTP-状态码"><a href="#HTTP-状态码" class="headerlink" title="HTTP 状态码"></a>HTTP 状态码</h2><p>服务器返回的 <strong>响应报文</strong> 中第一行为状态行，包含了状态码以及原因短语，用来告知客户端请求的结果。</p>
<table>
<thead>
<tr>
<th>状态码</th>
<th>类别</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>1XX</td>
<td>Informational（信息性状态码）</td>
<td>接收的请求正在处理</td>
</tr>
<tr>
<td>2XX</td>
<td>Success（成功状态码）</td>
<td>请求正常处理完毕</td>
</tr>
<tr>
<td>3XX</td>
<td>Redirection（重定向状态码）</td>
<td>需要进行附加操作以完成请求</td>
</tr>
<tr>
<td>4XX</td>
<td>Client Error（客户端错误状态码）</td>
<td>服务器无法处理请求</td>
</tr>
<tr>
<td>5XX</td>
<td>Server Error（服务器错误状态码）</td>
<td>服务器处理请求出错</td>
</tr>
</tbody></table>
<h3 id="1XX-信息"><a href="#1XX-信息" class="headerlink" title="1XX 信息"></a>1XX 信息</h3><ul>
<li><strong>100 Continue</strong> ：表明到目前为止都很正常，客户端可以继续发送请求或者忽略这个响应。</li>
</ul>
<h3 id="2XX-成功"><a href="#2XX-成功" class="headerlink" title="2XX 成功"></a>2XX 成功</h3><ul>
<li><strong>200 OK</strong></li>
<li><strong>204 No Content</strong> ：请求已经成功处理，但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息，而不需要返回数据时使用。</li>
<li><strong>206 Partial Content</strong> ：表示客户端进行了范围请求，响应报文包含由 Content-Range 指定范围的实体内容。</li>
</ul>
<h3 id="3XX-重定向"><a href="#3XX-重定向" class="headerlink" title="3XX 重定向"></a>3XX 重定向</h3><ul>
<li><strong>301 Moved Permanently</strong> ：永久性重定向</li>
<li><strong>302 Found</strong> ：临时性重定向</li>
<li><strong>303 See Other</strong> ：和 302 有着相同的功能，但是 303 明确要求客户端应该采用 GET 方法获取资源。</li>
<li>注：虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法，但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。</li>
<li><strong>304 Not Modified</strong> ：如果请求报文首部包含一些条件，例如：If-Match，If-Modified-Since，If-None-Match，If-Range，If-Unmodified-Since，如果不满足条件，则服务器会返回 304 状态码。</li>
<li><strong>307 Temporary Redirect</strong> ：临时重定向，与 302 的含义类似，但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。</li>
</ul>
<h3 id="4XX-客户端错误"><a href="#4XX-客户端错误" class="headerlink" title="4XX 客户端错误"></a>4XX 客户端错误</h3><ul>
<li><strong>400 Bad Request</strong> ：请求报文中存在语法错误。</li>
<li><strong>401 Unauthorized</strong> ：该状态码表示发送的请求需要有认证信息（BASIC 认证、DIGEST 认证）。如果之前已进行过一次请求，则表示用户认证失败。</li>
<li><strong>403 Forbidden</strong> ：请求被拒绝。</li>
<li><strong>404 Not Found</strong></li>
</ul>
<h3 id="5XX-服务器错误"><a href="#5XX-服务器错误" class="headerlink" title="5XX 服务器错误"></a>5XX 服务器错误</h3><ul>
<li><strong>500 Internal Server Error</strong> ：服务器正在执行请求时发生错误。</li>
<li><strong>503 Service Unavailable</strong> ：服务器暂时处于超负载或正在进行停机维护，现在无法处理请求。</li>
</ul>
<h2 id="HTTP-首部"><a href="#HTTP-首部" class="headerlink" title="HTTP 首部"></a>HTTP 首部</h2><p>有 4 种类型的首部字段：通用首部字段、请求首部字段、响应首部字段和实体首部字段。</p>
<p>各种首部字段及其含义如下（不需要全记，仅供查阅）：</p>
<h3 id="通用首部字段"><a href="#通用首部字段" class="headerlink" title="通用首部字段"></a>通用首部字段</h3><table>
<thead>
<tr>
<th>首部字段名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>Cache-Control</td>
<td>控制缓存的行为</td>
</tr>
<tr>
<td>Connection</td>
<td>控制不再转发给代理的首部字段、管理持久连接</td>
</tr>
<tr>
<td>Date</td>
<td>创建报文的日期时间</td>
</tr>
<tr>
<td>Pragma</td>
<td>报文指令</td>
</tr>
<tr>
<td>Trailer</td>
<td>报文末端的首部一览</td>
</tr>
<tr>
<td>Transfer-Encoding</td>
<td>指定报文主体的传输编码方式</td>
</tr>
<tr>
<td>Upgrade</td>
<td>升级为其他协议</td>
</tr>
<tr>
<td>Via</td>
<td>代理服务器的相关信息</td>
</tr>
<tr>
<td>Warning</td>
<td>错误通知</td>
</tr>
</tbody></table>
<h3 id="请求首部字段"><a href="#请求首部字段" class="headerlink" title="请求首部字段"></a>请求首部字段</h3><table>
<thead>
<tr>
<th>首部字段名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>Accept</td>
<td>用户代理可处理的媒体类型</td>
</tr>
<tr>
<td>Accept-Charset</td>
<td>优先的字符集</td>
</tr>
<tr>
<td>Accept-Encoding</td>
<td>优先的内容编码</td>
</tr>
<tr>
<td>Accept-Language</td>
<td>优先的语言（自然语言）</td>
</tr>
<tr>
<td>Authorization</td>
<td>Web 认证信息</td>
</tr>
<tr>
<td>Expect</td>
<td>期待服务器的特定行为</td>
</tr>
<tr>
<td>From</td>
<td>用户的电子邮箱地址</td>
</tr>
<tr>
<td>Host</td>
<td>请求资源所在服务器</td>
</tr>
<tr>
<td>If-Match</td>
<td>比较实体标记（ETag）</td>
</tr>
<tr>
<td>If-Modified-Since</td>
<td>比较资源的更新时间</td>
</tr>
<tr>
<td>If-None-Match</td>
<td>比较实体标记（与 If-Match 相反）</td>
</tr>
<tr>
<td>If-Range</td>
<td>资源未更新时发送实体 Byte 的范围请求</td>
</tr>
<tr>
<td>If-Unmodified-Since</td>
<td>比较资源的更新时间（与 If-Modified-Since 相反）</td>
</tr>
<tr>
<td>Max-Forwards</td>
<td>最大传输逐跳数</td>
</tr>
<tr>
<td>Proxy-Authorization</td>
<td>代理服务器要求客户端的认证信息</td>
</tr>
<tr>
<td>Range</td>
<td>实体的字节范围请求</td>
</tr>
<tr>
<td>Referer</td>
<td>对请求中 URI 的原始获取方</td>
</tr>
<tr>
<td>TE</td>
<td>传输编码的优先级</td>
</tr>
<tr>
<td>User-Agent</td>
<td>HTTP 客户端程序的信息</td>
</tr>
</tbody></table>
<h3 id="响应首部字段"><a href="#响应首部字段" class="headerlink" title="响应首部字段"></a>响应首部字段</h3><table>
<thead>
<tr>
<th>首部字段名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>Accept-Ranges</td>
<td>是否接受字节范围请求</td>
</tr>
<tr>
<td>Age</td>
<td>推算资源创建经过时间</td>
</tr>
<tr>
<td>ETag</td>
<td>资源的匹配信息</td>
</tr>
<tr>
<td>Location</td>
<td>令客户端重定向至指定 URI</td>
</tr>
<tr>
<td>Proxy-Authenticate</td>
<td>代理服务器对客户端的认证信息</td>
</tr>
<tr>
<td>Retry-After</td>
<td>对再次发起请求的时机要求</td>
</tr>
<tr>
<td>Server</td>
<td>HTTP 服务器的安装信息</td>
</tr>
<tr>
<td>Vary</td>
<td>代理服务器缓存的管理信息</td>
</tr>
<tr>
<td>WWW-Authenticate</td>
<td>服务器对客户端的认证信息</td>
</tr>
</tbody></table>
<h3 id="实体首部字段"><a href="#实体首部字段" class="headerlink" title="实体首部字段"></a>实体首部字段</h3><table>
<thead>
<tr>
<th>首部字段名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>Allow</td>
<td>资源可支持的 HTTP 方法</td>
</tr>
<tr>
<td>Content-Encoding</td>
<td>实体主体适用的编码方式</td>
</tr>
<tr>
<td>Content-Language</td>
<td>实体主体的自然语言</td>
</tr>
<tr>
<td>Content-Length</td>
<td>实体主体的大小</td>
</tr>
<tr>
<td>Content-Location</td>
<td>替代对应资源的 URI</td>
</tr>
<tr>
<td>Content-MD5</td>
<td>实体主体的报文摘要</td>
</tr>
<tr>
<td>Content-Range</td>
<td>实体主体的位置范围</td>
</tr>
<tr>
<td>Content-Type</td>
<td>实体主体的媒体类型</td>
</tr>
<tr>
<td>Expires</td>
<td>实体主体过期的日期时间</td>
</tr>
<tr>
<td>Last-Modified</td>
<td>资源的最后修改日期时间</td>
</tr>
</tbody></table>
<h2 id="具体应用"><a href="#具体应用" class="headerlink" title="具体应用"></a>具体应用</h2><h3 id="连接管理"><a href="#连接管理" class="headerlink" title="连接管理"></a>连接管理</h3><p><a href="https://camo.githubusercontent.com/d209aea05562d9c5eea22382e0d13e2d9fa286550034d311a160173967178db3/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f48545450315f785f436f6e6e656374696f6e732e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/d209aea05562d9c5eea22382e0d13e2d9fa286550034d311a160173967178db3/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f48545450315f785f436f6e6e656374696f6e732e706e67" alt="img"></a></p>
<h4 id="1-短连接与长连接"><a href="#1-短连接与长连接" class="headerlink" title="1. 短连接与长连接"></a>1. 短连接与长连接</h4><p>当浏览器访问一个包含多张图片的 HTML 页面时，除了请求访问的 HTML 页面资源，还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接，那么开销会很大。</p>
<p>长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。</p>
<ul>
<li>从 HTTP/1.1 开始默认是长连接的，如果要断开连接，需要由客户端或者服务器端提出断开，使用 <code>Connection : close</code>；</li>
<li>在 HTTP/1.1 之前默认是短连接的，如果需要使用长连接，则使用 <code>Connection : Keep-Alive</code>。</li>
</ul>
<h4 id="2-流水线"><a href="#2-流水线" class="headerlink" title="2. 流水线"></a>2. 流水线</h4><p>默认情况下，HTTP 请求是按顺序发出的，下一个请求只有在当前请求收到响应之后才会被发出。由于受到网络延迟和带宽的限制，在下一个请求被发送到服务器之前，可能需要等待很长时间。</p>
<p>流水线是在同一条长连接上连续发出请求，而不用等待响应返回，这样可以减少延迟。</p>
<h3 id="Cookie"><a href="#Cookie" class="headerlink" title="Cookie"></a>Cookie</h3><p>HTTP 协议是无状态的，主要是为了让 HTTP 协议尽可能简单，使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。</p>
<p>Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据，它会在浏览器之后向同一服务器再次发起请求时被携带上，用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据，因此会带来额外的性能开销（尤其是在移动环境下）。</p>
<p>Cookie 曾一度用于客户端数据的存储，因为当时并没有其它合适的存储办法而作为唯一的存储手段，但现在随着现代浏览器开始支持各种各样的存储方式，Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地，如使用 Web storage API（本地存储和会话存储）或 IndexedDB。</p>
<h4 id="1-用途"><a href="#1-用途" class="headerlink" title="1. 用途"></a>1. 用途</h4><ul>
<li>会话状态管理（如用户登录状态、购物车、游戏分数或其它需要记录的信息）</li>
<li>个性化设置（如用户自定义设置、主题等）</li>
<li>浏览器行为跟踪（如跟踪分析用户行为等）</li>
</ul>
<h4 id="2-创建过程"><a href="#2-创建过程" class="headerlink" title="2. 创建过程"></a>2. 创建过程</h4><p>服务器发送的响应报文包含 Set-Cookie 首部字段，客户端得到响应报文后把 Cookie 内容保存到浏览器中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">HTTP&#x2F;1.0 200 OK</span><br><span class="line">Content-type: text&#x2F;html</span><br><span class="line">Set-Cookie: yummy_cookie&#x3D;choco</span><br><span class="line">Set-Cookie: tasty_cookie&#x3D;strawberry</span><br><span class="line"></span><br><span class="line">[page content]</span><br></pre></td></tr></table></figure>

<p>客户端之后对同一个服务器发送请求时，会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GET &#x2F;sample_page.html HTTP&#x2F;1.1</span><br><span class="line">Host: www.example.org</span><br><span class="line">Cookie: yummy_cookie&#x3D;choco; tasty_cookie&#x3D;strawberry</span><br></pre></td></tr></table></figure>

<h4 id="3-分类"><a href="#3-分类" class="headerlink" title="3. 分类"></a>3. 分类</h4><ul>
<li>会话期 Cookie：浏览器关闭之后它会被自动删除，也就是说它仅在会话期内有效。</li>
<li>持久性 Cookie：指定过期时间（Expires）或有效期（max-age）之后就成为了持久性的 Cookie。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Set-Cookie: id&#x3D;a3fWa; Expires&#x3D;Wed, 21 Oct 2015 07:28:00 GMT;</span><br></pre></td></tr></table></figure>

<h4 id="4-作用域"><a href="#4-作用域" class="headerlink" title="4. 作用域"></a>4. 作用域</h4><p>Domain 标识指定了哪些主机可以接受 Cookie。如果不指定，默认为当前文档的主机（不包含子域名）。如果指定了 Domain，则一般包含子域名。例如，如果设置 Domain=mozilla.org，则 Cookie 也包含在子域名中（如 developer.mozilla.org）。</p>
<p>Path 标识指定了主机下的哪些路径可以接受 Cookie（该 URL 路径必须存在于请求 URL 中）。以字符 %x2F (“/“) 作为路径分隔符，子路径也会被匹配。例如，设置 Path=/docs，则以下地址都会匹配：</p>
<ul>
<li>/docs</li>
<li>/docs/Web/</li>
<li>/docs/Web/HTTP</li>
</ul>
<h4 id="5-JavaScript"><a href="#5-JavaScript" class="headerlink" title="5. JavaScript"></a>5. JavaScript</h4><p>浏览器通过 <code>document.cookie</code> 属性可创建新的 Cookie，也可通过该属性访问非 HttpOnly 标记的 Cookie。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">document.cookie &#x3D; &quot;yummy_cookie&#x3D;choco&quot;;</span><br><span class="line">document.cookie &#x3D; &quot;tasty_cookie&#x3D;strawberry&quot;;</span><br><span class="line">console.log(document.cookie);</span><br></pre></td></tr></table></figure>

<h4 id="6-HttpOnly"><a href="#6-HttpOnly" class="headerlink" title="6. HttpOnly"></a>6. HttpOnly</h4><p>标记为 HttpOnly 的 Cookie 不能被 JavaScript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的 <code>document.cookie</code> API 窃取用户的 Cookie 信息，因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Set-Cookie: id&#x3D;a3fWa; Expires&#x3D;Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly</span><br></pre></td></tr></table></figure>

<h4 id="7-Secure"><a href="#7-Secure" class="headerlink" title="7. Secure"></a>7. Secure</h4><p>标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记，敏感信息也不应该通过 Cookie 传输，因为 Cookie 有其固有的不安全性，Secure 标记也无法提供确实的安全保障。</p>
<h4 id="8-Session"><a href="#8-Session" class="headerlink" title="8. Session"></a>8. Session</h4><p>除了可以将用户信息通过 Cookie 存储在用户浏览器中，也可以利用 Session 存储在服务器端，存储在服务器端的信息更加安全。</p>
<p>Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中，效率会更高。</p>
<p>使用 Session 维护用户登录状态的过程如下：</p>
<ul>
<li>用户进行登录时，用户提交包含用户名和密码的表单，放入 HTTP 请求报文中；</li>
<li>服务器验证该用户名和密码，如果正确则把用户信息存储到 Redis 中，它在 Redis 中的 Key 称为 Session ID；</li>
<li>服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID，客户端收到响应报文之后将该 Cookie 值存入浏览器中；</li>
<li>客户端之后对同一个服务器进行请求时会包含该 Cookie 值，服务器收到之后提取出 Session ID，从 Redis 中取出用户信息，继续之前的业务操作。</li>
</ul>
<p>应该注意 Session ID 的安全性问题，不能让它被恶意攻击者轻易获取，那么就不能产生一个容易被猜到的 Session ID 值。此外，还需要经常重新生成 Session ID。在对安全性要求极高的场景下，例如转账等操作，除了使用 Session 管理用户状态之外，还需要对用户进行重新验证，比如重新输入密码，或者使用短信验证码等方式。</p>
<h4 id="9-浏览器禁用-Cookie"><a href="#9-浏览器禁用-Cookie" class="headerlink" title="9. 浏览器禁用 Cookie"></a>9. 浏览器禁用 Cookie</h4><p>此时无法使用 Cookie 来保存用户信息，只能使用 Session。除此之外，不能再将 Session ID 存放到 Cookie 中，而是使用 URL 重写技术，将 Session ID 作为 URL 的参数进行传递。</p>
<h4 id="10-Cookie-与-Session-选择"><a href="#10-Cookie-与-Session-选择" class="headerlink" title="10. Cookie 与 Session 选择"></a>10. Cookie 与 Session 选择</h4><ul>
<li>Cookie 只能存储 ASCII 码字符串，而 Session 则可以存储任何类型的数据，因此在考虑数据复杂性时首选 Session；</li>
<li>Cookie 存储在浏览器中，容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中，可以将 Cookie 值进行加密，然后在服务器进行解密；</li>
<li>对于大型网站，如果用户所有的信息都存储在 Session 中，那么开销是非常大的，因此不建议将所有的用户信息都存储到 Session 中。</li>
</ul>
<h3 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h3><h4 id="1-优点"><a href="#1-优点" class="headerlink" title="1. 优点"></a>1. 优点</h4><ul>
<li>缓解服务器压力；</li>
<li>降低客户端获取资源的延迟：缓存通常位于内存中，读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近，例如浏览器缓存。</li>
</ul>
<h4 id="2-实现方法"><a href="#2-实现方法" class="headerlink" title="2. 实现方法"></a>2. 实现方法</h4><ul>
<li>让代理服务器进行缓存；</li>
<li>让客户端浏览器进行缓存。</li>
</ul>
<h4 id="3-Cache-Control"><a href="#3-Cache-Control" class="headerlink" title="3. Cache-Control"></a>3. Cache-Control</h4><p>HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。</p>
<p><strong>3.1 禁止进行缓存</strong></p>
<p>no-store 指令规定不能对请求或响应的任何一部分进行缓存。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: no-store</span><br></pre></td></tr></table></figure>

<p><strong>3.2 强制确认缓存</strong></p>
<p>no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性，只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: no-cache</span><br></pre></td></tr></table></figure>

<p><strong>3.3 私有缓存和公共缓存</strong></p>
<p>private 指令规定了将资源作为私有缓存，只能被单独用户使用，一般存储在用户浏览器中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: private</span><br></pre></td></tr></table></figure>

<p>public 指令规定了将资源作为公共缓存，可以被多个用户使用，一般存储在代理服务器中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: public</span><br></pre></td></tr></table></figure>

<p><strong>3.4 缓存过期机制</strong></p>
<p>max-age 指令出现在请求报文，并且缓存资源的缓存时间小于该指令指定的时间，那么就能接受该缓存。</p>
<p>max-age 指令出现在响应报文，表示缓存资源在缓存服务器中保存的时间。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: max-age&#x3D;31536000</span><br></pre></td></tr></table></figure>

<p>Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Expires: Wed, 04 Jul 2012 08:26:05 GMT</span><br></pre></td></tr></table></figure>

<ul>
<li>在 HTTP/1.1 中，会优先处理 max-age 指令；</li>
<li>在 HTTP/1.0 中，max-age 指令会被忽略掉。</li>
</ul>
<h4 id="4-缓存验证"><a href="#4-缓存验证" class="headerlink" title="4. 缓存验证"></a>4. 缓存验证</h4><p>需要先了解 ETag 首部字段的含义，它是资源的唯一标识。URL 不能唯一表示资源，例如 <code>http://www.google.com/</code> 有中文和英文两个资源，只有 ETag 才能对这两个资源进行唯一标识。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ETag: &quot;82e22293907ce725faf67773957acd12&quot;</span><br></pre></td></tr></table></figure>

<p>可以将缓存资源的 ETag 值放入 If-None-Match 首部，服务器收到该请求后，判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致，如果一致则表示缓存资源有效，返回 304 Not Modified。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">If-None-Match: &quot;82e22293907ce725faf67773957acd12&quot;</span><br></pre></td></tr></table></figure>

<p>Last-Modified 首部字段也可以用于缓存验证，它包含在源服务器发送的响应报文中，指示源服务器对资源的最后修改时间。但是它是一种弱校验器，因为只能精确到一秒，所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息，客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回，状态码为 200 OK。如果请求的资源从那时起未经修改，那么返回一个不带有实体主体的 304 Not Modified 响应报文。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT</span><br><span class="line">If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT</span><br></pre></td></tr></table></figure>

<h3 id="内容协商"><a href="#内容协商" class="headerlink" title="内容协商"></a>内容协商</h3><p>通过内容协商返回最合适的内容，例如根据浏览器的默认语言选择返回中文界面还是英文界面。</p>
<h4 id="1-类型"><a href="#1-类型" class="headerlink" title="1. 类型"></a>1. 类型</h4><p><strong>1.1 服务端驱动型</strong></p>
<p>客户端设置特定的 HTTP 首部字段，例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language，服务器根据这些字段返回特定的资源。</p>
<p>它存在以下问题：</p>
<ul>
<li>服务器很难知道客户端浏览器的全部信息；</li>
<li>客户端提供的信息相当冗长（HTTP/2 协议的首部压缩机制缓解了这个问题），并且存在隐私风险（HTTP 指纹识别技术）；</li>
<li>给定的资源需要返回不同的展现形式，共享缓存的效率会降低，而服务器端的实现会越来越复杂。</li>
</ul>
<p><strong>1.2 代理驱动型</strong></p>
<p>服务器返回 300 Multiple Choices 或者 406 Not Acceptable，客户端从中选出最合适的那个资源。</p>
<h4 id="2-Vary"><a href="#2-Vary" class="headerlink" title="2. Vary"></a>2. Vary</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Vary: Accept-Language</span><br></pre></td></tr></table></figure>

<p>在使用内容协商的情况下，只有当缓存服务器中的缓存满足内容协商条件时，才能使用该缓存，否则应该向源服务器请求该资源。</p>
<p>例如，一个客户端发送了一个包含 Accept-Language 首部字段的请求之后，源服务器返回的响应包含 <code>Vary: Accept-Language</code> 内容，缓存服务器对这个响应进行缓存之后，在客户端下一次访问同一个 URL 资源，并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。</p>
<h3 id="内容编码"><a href="#内容编码" class="headerlink" title="内容编码"></a>内容编码</h3><p>内容编码将实体主体进行压缩，从而减少传输的数据量。</p>
<p>常用的内容编码有：gzip、compress、deflate、identity。</p>
<p>浏览器发送 Accept-Encoding 首部，其中包含有它所支持的压缩算法，以及各自的优先级。服务器则从中选择一种，使用该算法对响应的消息主体进行压缩，并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的，响应报文的 Vary 首部字段至少要包含 Content-Encoding。</p>
<h3 id="范围请求"><a href="#范围请求" class="headerlink" title="范围请求"></a>范围请求</h3><p>如果网络出现中断，服务器只发送了一部分数据，范围请求可以使得客户端只请求服务器未发送的那部分数据，从而避免服务器重新发送所有数据。</p>
<h4 id="1-Range"><a href="#1-Range" class="headerlink" title="1. Range"></a>1. Range</h4><p>在请求报文中添加 Range 首部字段指定请求的范围。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GET &#x2F;z4d4kWk.jpg HTTP&#x2F;1.1</span><br><span class="line">Host: i.imgur.com</span><br><span class="line">Range: bytes&#x3D;0-1023</span><br></pre></td></tr></table></figure>

<p>请求成功的话服务器返回的响应包含 206 Partial Content 状态码。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">HTTP&#x2F;1.1 206 Partial Content</span><br><span class="line">Content-Range: bytes 0-1023&#x2F;146515</span><br><span class="line">Content-Length: 1024</span><br><span class="line">...</span><br><span class="line">(binary content)</span><br></pre></td></tr></table></figure>

<h4 id="2-Accept-Ranges"><a href="#2-Accept-Ranges" class="headerlink" title="2. Accept-Ranges"></a>2. Accept-Ranges</h4><p>响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求，可以处理使用 bytes，否则使用 none。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Accept-Ranges: bytes</span><br></pre></td></tr></table></figure>

<h4 id="3-响应状态码"><a href="#3-响应状态码" class="headerlink" title="3. 响应状态码"></a>3. 响应状态码</h4><ul>
<li>在请求成功的情况下，服务器会返回 206 Partial Content 状态码。</li>
<li>在请求的范围越界的情况下，服务器会返回 416 Requested Range Not Satisfiable 状态码。</li>
<li>在不支持范围请求的情况下，服务器会返回 200 OK 状态码。</li>
</ul>
<h3 id="分块传输编码"><a href="#分块传输编码" class="headerlink" title="分块传输编码"></a>分块传输编码</h3><p>Chunked Transfer Encoding，可以把数据分割成多块，让浏览器逐步显示页面。</p>
<h3 id="多部分对象集合"><a href="#多部分对象集合" class="headerlink" title="多部分对象集合"></a>多部分对象集合</h3><p>一份报文主体内可含有多种类型的实体同时发送，每个部分之间用 boundary 字段定义的分隔符进行分隔，每个部分都可以有首部字段。</p>
<p>例如，上传多个表单时可以使用如下方式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Content-Type: multipart&#x2F;form-data; boundary&#x3D;AaB03x</span><br><span class="line"></span><br><span class="line">--AaB03x</span><br><span class="line">Content-Disposition: form-data; name&#x3D;&quot;submit-name&quot;</span><br><span class="line"></span><br><span class="line">Larry</span><br><span class="line">--AaB03x</span><br><span class="line">Content-Disposition: form-data; name&#x3D;&quot;files&quot;; filename&#x3D;&quot;file1.txt&quot;</span><br><span class="line">Content-Type: text&#x2F;plain</span><br><span class="line"></span><br><span class="line">... contents of file1.txt ...</span><br><span class="line">--AaB03x--</span><br></pre></td></tr></table></figure>

<h3 id="虚拟主机"><a href="#虚拟主机" class="headerlink" title="虚拟主机"></a>虚拟主机</h3><p>HTTP/1.1 使用虚拟主机技术，使得一台服务器拥有多个域名，并且在逻辑上可以看成多个服务器。</p>
<h3 id="通信数据转发"><a href="#通信数据转发" class="headerlink" title="通信数据转发"></a>通信数据转发</h3><h4 id="1-代理"><a href="#1-代理" class="headerlink" title="1. 代理"></a>1. 代理</h4><p>代理服务器接受客户端的请求，并且转发给其它服务器。</p>
<p>使用代理的主要目的是：</p>
<ul>
<li>缓存</li>
<li>负载均衡</li>
<li>网络访问控制</li>
<li>访问日志记录</li>
</ul>
<p>代理服务器分为正向代理和反向代理两种：</p>
<ul>
<li>用户察觉得到正向代理的存在。</li>
</ul>
<p><a href="https://camo.githubusercontent.com/59fcedfd5852a065a1326436754e02245537d4d3876ca015fcb86a5932de7452/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f61333134626237392d356231382d346536332d613937362d3334343862666661366631622e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/59fcedfd5852a065a1326436754e02245537d4d3876ca015fcb86a5932de7452/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f61333134626237392d356231382d346536332d613937362d3334343862666661366631622e706e67" alt="img"></a></p>
<ul>
<li>而反向代理一般位于内部网络中，用户察觉不到。</li>
</ul>
<p><a href="https://camo.githubusercontent.com/e3072be9388f44c38c28b346e278fb02f81db7a88bab25efc8aa0076b496db0f/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f32643039613834372d623835342d343339632d393139382d6232396336353831303934342e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/e3072be9388f44c38c28b346e278fb02f81db7a88bab25efc8aa0076b496db0f/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f32643039613834372d623835342d343339632d393139382d6232396336353831303934342e706e67" alt="img"></a></p>
<h4 id="2-网关"><a href="#2-网关" class="headerlink" title="2. 网关"></a>2. 网关</h4><p>与代理服务器不同的是，网关服务器会将 HTTP 转化为其它协议进行通信，从而请求其它非 HTTP 服务器的服务。</p>
<h4 id="3-隧道"><a href="#3-隧道" class="headerlink" title="3. 隧道"></a>3. 隧道</h4><p>使用 SSL 等加密手段，在客户端和服务器之间建立一条安全的通信线路。</p>
<h2 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h2><p>HTTP 有以下安全性问题：</p>
<ul>
<li>使用明文进行通信，内容可能会被窃听；</li>
<li>不验证通信方的身份，通信方的身份有可能遭遇伪装；</li>
<li>无法证明报文的完整性，报文有可能遭篡改。</li>
</ul>
<p>HTTPS 并不是新协议，而是让 HTTP 先和 SSL（Secure Sockets Layer）通信，再由 SSL 和 TCP 通信，也就是说 HTTPS 使用了隧道进行通信。</p>
<p>通过使用 SSL，HTTPS 具有了加密（防窃听）、认证（防伪装）和完整性保护（防篡改）。</p>
<p><a href="https://camo.githubusercontent.com/d742fcbc48d96d10aeb1996c62410acac607e421adb44cc544105f1f84c3b284/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f73736c2d6f66666c6f6164696e672e6a7067" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/d742fcbc48d96d10aeb1996c62410acac607e421adb44cc544105f1f84c3b284/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f73736c2d6f66666c6f6164696e672e6a7067" alt="img"></a></p>
<h3 id="加密"><a href="#加密" class="headerlink" title="加密"></a>加密</h3><h4 id="1-对称密钥加密"><a href="#1-对称密钥加密" class="headerlink" title="1. 对称密钥加密"></a>1. 对称密钥加密</h4><p>对称密钥加密（Symmetric-Key Encryption），加密和解密使用同一密钥。</p>
<ul>
<li>优点：运算速度快；</li>
<li>缺点：无法安全地将密钥传输给通信方。</li>
</ul>
<p><a href="https://camo.githubusercontent.com/6c294912997faa05a28d069a85582276f8885e1e5fd8cea3318239f2d2bb08ea/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f37666666613462382d623336642d343731662d616430632d6138386565373633626237362e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/6c294912997faa05a28d069a85582276f8885e1e5fd8cea3318239f2d2bb08ea/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f37666666613462382d623336642d343731662d616430632d6138386565373633626237362e706e67" alt="img"></a></p>
<h4 id="2-非对称密钥加密"><a href="#2-非对称密钥加密" class="headerlink" title="2.非对称密钥加密"></a>2.非对称密钥加密</h4><p>非对称密钥加密，又称公开密钥加密（Public-Key Encryption），加密和解密使用不同的密钥。</p>
<p>公开密钥所有人都可以获得，通信发送方获得接收方的公开密钥之后，就可以使用公开密钥进行加密，接收方收到通信内容后使用私有密钥解密。</p>
<p>非对称密钥除了用来加密，还可以用来进行签名。因为私有密钥无法被其他人获取，因此通信发送方使用其私有密钥进行签名，通信接收方使用发送方的公开密钥对签名进行解密，就能判断这个签名是否正确。</p>
<ul>
<li>优点：可以更安全地将公开密钥传输给通信发送方；</li>
<li>缺点：运算速度慢。</li>
</ul>
<p><a href="https://camo.githubusercontent.com/8ebc0cef52df1490899222ffeb3fa231bc19a2f2eb8fb32dac0611af865ea577/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f33396363623239392d656539392d346464312d623862342d3266396563393439356362342e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/8ebc0cef52df1490899222ffeb3fa231bc19a2f2eb8fb32dac0611af865ea577/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f33396363623239392d656539392d346464312d623862342d3266396563393439356362342e706e67" alt="img"></a></p>
<h4 id="3-HTTPS-采用的加密方式"><a href="#3-HTTPS-采用的加密方式" class="headerlink" title="3. HTTPS 采用的加密方式"></a>3. HTTPS 采用的加密方式</h4><p>上面提到对称密钥加密方式的传输效率更高，但是无法安全地将密钥 Secret Key 传输给通信方。而非对称密钥加密方式可以保证传输的安全性，因此我们可以利用非对称密钥加密方式将 Secret Key 传输给通信方。HTTPS 采用混合的加密机制，正是利用了上面提到的方案：</p>
<ul>
<li>使用非对称密钥加密方式，传输对称密钥加密方式所需要的 Secret Key，从而保证安全性;</li>
<li>获取到 Secret Key 后，再使用对称密钥加密方式进行通信，从而保证效率。（下图中的 Session Key 就是 Secret Key）</li>
</ul>
<p><a href="https://camo.githubusercontent.com/34cc60de23ad2228d3877e97ed1605fa9b858dda8610de5e3201144e3b35983a/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f486f772d48545450532d576f726b732e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/34cc60de23ad2228d3877e97ed1605fa9b858dda8610de5e3201144e3b35983a/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f486f772d48545450532d576f726b732e706e67" alt="img"></a></p>
<h3 id="认证"><a href="#认证" class="headerlink" title="认证"></a>认证</h3><p>通过使用 <strong>证书</strong> 来对通信方进行认证。</p>
<p>数字证书认证机构（CA，Certificate Authority）是客户端与服务器双方都可信赖的第三方机构。</p>
<p>服务器的运营人员向 CA 提出公开密钥的申请，CA 在判明提出申请者的身份之后，会对已申请的公开密钥做数字签名，然后分配这个已签名的公开密钥，并将该公开密钥放入公开密钥证书后绑定在一起。</p>
<p>进行 HTTPS 通信时，服务器会把证书发送给客户端。客户端取得其中的公开密钥之后，先使用数字签名进行验证，如果验证通过，就可以开始通信了。</p>
<p><a href="https://camo.githubusercontent.com/f4df5d88f1f914fc81325b00151cefea3994c36827fd18c2a1a5e9f7582e4746/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f323031372d30362d31312d63612e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/f4df5d88f1f914fc81325b00151cefea3994c36827fd18c2a1a5e9f7582e4746/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f323031372d30362d31312d63612e706e67" alt="img"></a></p>
<h3 id="完整性保护"><a href="#完整性保护" class="headerlink" title="完整性保护"></a>完整性保护</h3><p>SSL 提供报文摘要功能来进行完整性保护。</p>
<p>HTTP 也提供了 MD5 报文摘要功能，但不是安全的。例如报文内容被篡改之后，同时重新计算 MD5 的值，通信接收方是无法意识到发生了篡改。</p>
<p>HTTPS 的报文摘要功能之所以安全，是因为它结合了加密和认证这两个操作。试想一下，加密之后的报文，遭到篡改之后，也很难重新计算报文摘要，因为无法轻易获取明文。</p>
<h3 id="HTTPS-的缺点"><a href="#HTTPS-的缺点" class="headerlink" title="HTTPS 的缺点"></a>HTTPS 的缺点</h3><ul>
<li>因为需要进行加密解密等过程，因此速度会更慢；</li>
<li>需要支付证书授权的高额费用。</li>
</ul>
<h2 id="HTTP-2-0"><a href="#HTTP-2-0" class="headerlink" title="HTTP/2.0"></a>HTTP/2.0</h2><h3 id="HTTP-1-x-缺陷"><a href="#HTTP-1-x-缺陷" class="headerlink" title="HTTP/1.x 缺陷"></a>HTTP/1.x 缺陷</h3><p>HTTP/1.x 实现简单是以牺牲性能为代价的：</p>
<ul>
<li>客户端需要使用多个连接才能实现并发和缩短延迟；</li>
<li>不会压缩请求和响应首部，从而导致不必要的网络流量；</li>
<li>不支持有效的资源优先级，致使底层 TCP 连接的利用率低下。</li>
</ul>
<h3 id="二进制分帧层"><a href="#二进制分帧层" class="headerlink" title="二进制分帧层"></a>二进制分帧层</h3><p>HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧，它们都是二进制格式的。</p>
<p><a href="https://camo.githubusercontent.com/c96cfc774e63ed7fc74c55454a55212d64bc01ebdd0650cb95e68f944b88eae0/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f38366536613931642d613238352d343437612d393334352d6335343834623864306334372e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/c96cfc774e63ed7fc74c55454a55212d64bc01ebdd0650cb95e68f944b88eae0/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f38366536613931642d613238352d343437612d393334352d6335343834623864306334372e706e67" alt="img"></a></p>
<p>在通信过程中，只会有一个 TCP 连接存在，它承载了任意数量的双向数据流（Stream）。</p>
<ul>
<li>一个数据流（Stream）都有一个唯一标识符和可选的优先级信息，用于承载双向信息。</li>
<li>消息（Message）是与逻辑请求或响应对应的完整的一系列帧。</li>
<li>帧（Frame）是最小的通信单位，来自不同数据流的帧可以交错发送，然后再根据每个帧头的数据流标识符重新组装。</li>
</ul>
<p><a href="https://camo.githubusercontent.com/61880e95d65b2cf50737eca087e7a62ecff552c7e0f0c9a66b928488968b98a6/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f61663139386461312d323438302d343034332d623037662d6133623931613838623831352e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/61880e95d65b2cf50737eca087e7a62ecff552c7e0f0c9a66b928488968b98a6/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f61663139386461312d323438302d343034332d623037662d6133623931613838623831352e706e67" alt="img"></a></p>
<h3 id="服务端推送"><a href="#服务端推送" class="headerlink" title="服务端推送"></a>服务端推送</h3><p>HTTP/2.0 在客户端请求一个资源时，会把相关的资源一起发送给客户端，客户端就不需要再次发起请求了。例如客户端请求 page.html 页面，服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。</p>
<p><a href="https://camo.githubusercontent.com/4d8039e63487da06628fab7284a7fe61f58e94d46184bc510b44ab95a43d82be/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f65336631363537632d383066632d346466612d393634332d6266353161626432303163362e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/4d8039e63487da06628fab7284a7fe61f58e94d46184bc510b44ab95a43d82be/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f65336631363537632d383066632d346466612d393634332d6266353161626432303163362e706e67" alt="img"></a></p>
<h3 id="首部压缩"><a href="#首部压缩" class="headerlink" title="首部压缩"></a>首部压缩</h3><p>HTTP/1.1 的首部带有大量信息，而且每次都要重复发送。</p>
<p>HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表，从而避免了重复传输。</p>
<p>不仅如此，HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。</p>
<p><a href="https://camo.githubusercontent.com/c80b3a5fca38bd0d74330acae8f6bd351a22185ec0ed50b639a461a096eedbe1/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f5f75344530425f75384637442e706e67" target="_blank" rel="noopener"><img data-src="https://camo.githubusercontent.com/c80b3a5fca38bd0d74330acae8f6bd351a22185ec0ed50b639a461a096eedbe1/68747470733a2f2f63732d6e6f7465732d313235363130393739362e636f732e61702d6775616e677a686f752e6d7971636c6f75642e636f6d2f5f75344530425f75384637442e706e67" alt="img"></a></p>
<h2 id="HTTP-1-1-新特性"><a href="#HTTP-1-1-新特性" class="headerlink" title="HTTP/1.1 新特性"></a>HTTP/1.1 新特性</h2><p>详细内容请见上文</p>
<ul>
<li>默认是长连接</li>
<li>支持流水线</li>
<li>支持同时打开多个 TCP 连接</li>
<li>支持虚拟主机</li>
<li>新增状态码 100</li>
<li>支持分块传输编码</li>
<li>新增缓存处理指令 max-age</li>
</ul>
<h2 id="GET-和-POST-比较"><a href="#GET-和-POST-比较" class="headerlink" title="GET 和 POST 比较"></a>GET 和 POST 比较</h2><h3 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h3><p>GET 用于获取资源，而 POST 用于传输实体主体。</p>
<h3 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h3><p>GET 和 POST 的请求都能使用额外的参数，但是 GET 的参数是以查询字符串出现在 URL 中，而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高，因为照样可以通过一些抓包工具（Fiddler）查看。</p>
<p>因为 URL 只支持 ASCII 码，因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 <code>中文</code> 会转换为 <code>%E4%B8%AD%E6%96%87</code>，而空格会转换为 <code>%20</code>。POST 参数支持标准字符集。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">GET &#x2F;test&#x2F;demo_form.asp?name1&#x3D;value1&amp;name2&#x3D;value2 HTTP&#x2F;1.1</span><br><span class="line">POST &#x2F;test&#x2F;demo_form.asp HTTP&#x2F;1.1</span><br><span class="line">Host: w3schools.com</span><br><span class="line">name1&#x3D;value1&amp;name2&#x3D;value2</span><br></pre></td></tr></table></figure>

<h3 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h3><p>安全的 HTTP 方法不会改变服务器状态，也就是说它只是可读的。</p>
<p>GET 方法是安全的，而 POST 却不是，因为 POST 的目的是传送实体主体内容，这个内容可能是用户上传的表单数据，上传成功之后，服务器可能把这个数据存储到数据库中，因此状态也就发生了改变。</p>
<p>安全的方法除了 GET 之外还有：HEAD、OPTIONS。</p>
<p>不安全的方法除了 POST 之外还有 PUT、DELETE。</p>
<h3 id="幂等性"><a href="#幂等性" class="headerlink" title="幂等性"></a>幂等性</h3><p>幂等的 HTTP 方法，同样的请求被执行一次与连续执行多次的效果是一样的，服务器的状态也是一样的。换句话说就是，幂等方法不应该具有副作用（统计用途除外）。</p>
<p>所有的安全方法也都是幂等的。</p>
<p>在正确实现的条件下，GET，HEAD，PUT 和 DELETE 等方法都是幂等的，而 POST 方法不是。</p>
<p>GET /pageX HTTP/1.1 是幂等的，连续调用多次，客户端接收到的结果都是一样的：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">GET &#x2F;pageX HTTP&#x2F;1.1</span><br><span class="line">GET &#x2F;pageX HTTP&#x2F;1.1</span><br><span class="line">GET &#x2F;pageX HTTP&#x2F;1.1</span><br><span class="line">GET &#x2F;pageX HTTP&#x2F;1.1</span><br></pre></td></tr></table></figure>

<p>POST /add_row HTTP/1.1 不是幂等的，如果调用多次，就会增加多行记录：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">POST &#x2F;add_row HTTP&#x2F;1.1   -&gt; Adds a 1nd row</span><br><span class="line">POST &#x2F;add_row HTTP&#x2F;1.1   -&gt; Adds a 2nd row</span><br><span class="line">POST &#x2F;add_row HTTP&#x2F;1.1   -&gt; Adds a 3rd row</span><br></pre></td></tr></table></figure>

<p>DELETE /idX/delete HTTP/1.1 是幂等的，即使不同的请求接收到的状态码不一样：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">DELETE &#x2F;idX&#x2F;delete HTTP&#x2F;1.1   -&gt; Returns 200 if idX exists</span><br><span class="line">DELETE &#x2F;idX&#x2F;delete HTTP&#x2F;1.1   -&gt; Returns 404 as it just got deleted</span><br><span class="line">DELETE &#x2F;idX&#x2F;delete HTTP&#x2F;1.1   -&gt; Returns 404</span><br></pre></td></tr></table></figure>

<h3 id="可缓存"><a href="#可缓存" class="headerlink" title="可缓存"></a>可缓存</h3><p>如果要对响应进行缓存，需要满足以下条件：</p>
<ul>
<li>请求报文的 HTTP 方法本身是可缓存的，包括 GET 和 HEAD，但是 PUT 和 DELETE 不可缓存，POST 在多数情况下不可缓存的。</li>
<li>响应报文的状态码是可缓存的，包括：200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。</li>
<li>响应报文的 Cache-Control 首部字段没有指定不进行缓存。</li>
</ul>
<h3 id="XMLHttpRequest"><a href="#XMLHttpRequest" class="headerlink" title="XMLHttpRequest"></a>XMLHttpRequest</h3><p>为了阐述 POST 和 GET 的另一个区别，需要先了解 XMLHttpRequest：</p>
<blockquote>
<p>XMLHttpRequest 是一个 API，它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式，并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。</p>
</blockquote>
<ul>
<li>在使用 XMLHttpRequest 的 POST 方法时，浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做，例如火狐就不会。</li>
<li>而 GET 方法 Header 和 Data 会一起发送。</li>
</ul>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li>上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP" target="_blank" rel="noopener">MDN : HTTP</a></li>
<li><a href="https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn" target="_blank" rel="noopener">HTTP/2 简介</a></li>
<li><a href="http://php.net/manual/zh/function.htmlspecialchars.php" target="_blank" rel="noopener">htmlspecialchars</a></li>
<li><a href="http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java" target="_blank" rel="noopener">Difference between file URI and URL in java</a></li>
<li><a href="https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement" target="_blank" rel="noopener">How to Fix SQL Injection Using Java PreparedStatement &amp; CallableStatement</a></li>
<li><a href="https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html" target="_blank" rel="noopener">浅谈 HTTP 中 Get 与 Post 的区别</a></li>
<li><a href="https://www.webdancers.com/are-http-and-www-necesary/" target="_blank" rel="noopener">Are http:// and www really necessary?</a></li>
<li><a href="https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html" target="_blank" rel="noopener">HTTP (HyperText Transfer Protocol)</a></li>
<li><a href="https://www.igvita.com/2011/12/01/web-vpn-secure-proxies-with-spdy-chrome/" target="_blank" rel="noopener">Web-VPN: Secure Proxies with SPDY &amp; Chrome</a></li>
<li><a href="http://en.wikipedia.org/wiki/File:HTTP_persistent_connection.svg" target="_blank" rel="noopener">File:HTTP persistent connection.svg</a></li>
<li><a href="https://en.wikipedia.org/wiki/Proxy_server" target="_blank" rel="noopener">Proxy server</a></li>
<li><a href="https://www.x-cart.com/blog/what-is-https-and-ssl.html" target="_blank" rel="noopener">What Is This HTTPS/SSL Thing And Why Should You Care?</a></li>
<li><a href="https://securebox.comodo.com/ssl-sniffing/ssl-offloading/" target="_blank" rel="noopener">What is SSL Offloading?</a></li>
<li><a href="https://docs.oracle.com/cd/E19424-01/820-4811/6ng8i26bn/index.html" target="_blank" rel="noopener">Sun Directory Server Enterprise Edition 7.0 Reference - Key Encryption</a></li>
<li><a href="https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication" target="_blank" rel="noopener">An Introduction to Mutual SSL Authentication</a></li>
<li><a href="https://danielmiessler.com/study/url-uri/" target="_blank" rel="noopener">The Difference Between URLs and URIs</a></li>
<li><a href="https://juejin.im/entry/5766c29d6be3ff006a31b84e#comment" target="_blank" rel="noopener">Cookie 与 Session 的区别</a></li>
<li><a href="https://www.zhihu.com/question/19786827" target="_blank" rel="noopener">COOKIE 和 SESSION 有什么区别</a></li>
<li><a href="https://harttle.land/2015/08/10/cookie-session.html" target="_blank" rel="noopener">Cookie/Session 的机制与安全</a></li>
<li><a href="https://shijianan.com/2017/06/11/https/" target="_blank" rel="noopener">HTTPS 证书原理</a></li>
<li><a href="https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn" target="_blank" rel="noopener">What is the difference between a URI, a URL and a URN?</a></li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest" target="_blank" rel="noopener">XMLHttpRequest</a></li>
<li><a href="https://blog.josephscott.org/2009/08/27/xmlhttprequest-xhr-uses-multiple-packets-for-http-post/" target="_blank" rel="noopener">XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?</a></li>
<li><a href="https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences" target="_blank" rel="noopener">Symmetric vs. Asymmetric Encryption – What are differences?</a></li>
<li><a href="https://www.kancloud.cn/digest/web-performance-http2" target="_blank" rel="noopener">Web 性能优化与 HTTP/2</a></li>
<li><a href="https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn" target="_blank" rel="noopener">HTTP/2 简介</a></li>
</ul>
<hr>
<p>转载自GitHub:</p>
<p><a href="https://github.com/CyC2018/CS-Notes/blob/master/notes/HTTP.md" target="_blank" rel="noopener">CyC2018 - CS-Notes</a></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/12/15/why-https-security/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/12/15/why-https-security/" class="post-title-link" itemprop="url">HTTPS 为什么是安全的</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-12-15 00:18:01" itemprop="dateCreated datePublished" datetime="2019-12-15T00:18:01+08:00">2019-12-15</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" itemprop="url" rel="index"><span itemprop="name">计算机网络</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/HTTP/" itemprop="url" rel="index"><span itemprop="name">HTTP</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>3k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>3 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <blockquote>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2></blockquote>
<p>在之前《HTTP 与 HTTPS 的区别》中，对比了<code>HTTP/HTTPS</code>的不同，以及<code>HTTP/HTTPS</code>是如何<code>TCP</code>握手的，那么HTTPS为什么是安全的？</p>
<p>超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息，HTTP协议以明文方式发送内容，不提供任何方式的数据加密，如果攻击者截取了Web浏览器和网站服务器之间的传输报文，就可以直接读懂其中的信息，因此，HTTP协议不适合传输一些敏感信息。</p>
<p>为了解决HTTP协议的这一缺陷，需要使用另一种协议：安全套接字层超文本传输协议HTTPS，为了数据传输的安全，HTTPS在HTTP的基础上加入了<code>SSL</code>协议，SSL依靠证书来验证服务器的身份，并为浏览器和服务器之间的通信加密。</p>
<h2 id="HTTP-协议"><a href="#HTTP-协议" class="headerlink" title="HTTP 协议"></a>HTTP 协议</h2><p>在谈论 HTTPS 协议之前，先来回顾一下 HTTP 协议的概念。</p>
<h3 id="HTTP-协议介绍"><a href="#HTTP-协议介绍" class="headerlink" title="HTTP 协议介绍"></a>HTTP 协议介绍</h3><p>HTTP 协议是一种基于文本的传输协议，它位于 OSI 网络模型中的<strong><code>应用层</code></strong>。</p>
<img data-src="/2019/12/15/why-https-security/osi-7layers.png" class>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2019/12/15/why-https-security/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/12/03/http-https/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/12/03/http-https/" class="post-title-link" itemprop="url">HTTP 与 HTTPS 的区别</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-12-03 00:03:49" itemprop="dateCreated datePublished" datetime="2019-12-03T00:03:49+08:00">2019-12-03</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" itemprop="url" rel="index"><span itemprop="name">计算机网络</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/HTTP/" itemprop="url" rel="index"><span itemprop="name">HTTP</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>2.2k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>2 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h1><p><strong>HTTP</strong>（HyperText Transfer Protocol：超文本传输协议）是一种用于分布式、协作式和超媒体信息系统的应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法，被用于在 Web 浏览器和网站服务器之间传递信息。</p>
<p>HTTP 默认工作在 TCP 协议 80 端口，用户访问网站 <strong><code>http://</code></strong> 打头的都是标准 HTTP 服务。</p>
<p>HTTP 协议以明文方式发送内容，不提供任何方式的数据加密，如果攻击者截取了Web浏览器和网站服务器之间的传输报文，就可以直接读懂其中的信息，因此，HTTP协议不适合传输一些敏感信息，比如：信用卡号、密码等支付信息。</p>
<p><strong>HTTPS</strong>（Hypertext Transfer Protocol Secure：超文本传输安全协议）是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信，但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的，是提供对网站服务器的身份认证，保护交换数据的隐私与完整性。</p>
<p>HTTPS 默认工作在 TCP 协议443端口，它的工作流程一般如以下方式：</p>
<ul>
<li>1、TCP 三次同步握手</li>
<li>2、客户端验证服务器数字证书</li>
<li>3、DH 算法协商对称加密算法的密钥、hash 算法的密钥</li>
<li>4、SSL 安全加密隧道协商完成</li>
<li>5、网页以加密的方式传输，用协商的对称加密算法和密钥加密，保证数据机密性；用协商的hash算法进行数据完整性保护，保证数据不被篡改。</li>
</ul>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2019/12/03/http-https/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/11/26/python-single-double-asterisk/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/26/python-single-double-asterisk/" class="post-title-link" itemprop="url">Python函数中参数 * 和 ** 的区别</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-11-26 00:28:55" itemprop="dateCreated datePublished" datetime="2019-11-26T00:28:55+08:00">2019-11-26</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Python/" itemprop="url" rel="index"><span itemprop="name">Python</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Python/%E5%9F%BA%E7%A1%80%E5%8E%9F%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">基础原理</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>677</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在 Python 的函数中经常能看到输入的参数前面有一个或者两个星号，例如：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">foo</span><span class="params">(param1, *param2)</span>:</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">bar</span><span class="params">(param1, **param2)</span>:</span></span><br></pre></td></tr></table></figure>

<p>这两种用法其实都是用来将任意个数的参数导入到 Python 函数中。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2019/11/26/python-single-double-asterisk/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/11/12/git-basis/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/12/git-basis/" class="post-title-link" itemprop="url">Git原理及实践</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-11-12 22:45:15" itemprop="dateCreated datePublished" datetime="2019-11-12T22:45:15+08:00">2019-11-12</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Git/" itemprop="url" rel="index"><span itemprop="name">Git</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>3.4k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>3 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="Git是什么"><a href="#Git是什么" class="headerlink" title="Git是什么?"></a>Git是什么?</h1><h2 id="什么是版本控制？"><a href="#什么是版本控制？" class="headerlink" title="什么是版本控制？"></a>什么是版本控制？</h2><p>版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理，是软件配置管理的核心思想之一。</p>
<h2 id="什么是Git"><a href="#什么是Git" class="headerlink" title="什么是Git?"></a>什么是Git?</h2><p><img data-src="/picture/git_logo.png" alt="avatar"><br>Git 是一个开源的分布式版本控制系统，用于敏捷高效地处理任何或小或大的项目。<br>Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。<br>Git 与常用的版本控制工具 CVS， Subversion 等不同，它采用了分布式版本库的方式，不必服务器端软件支持。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2019/11/12/git-basis/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://notspr.com/2019/10/19/first-blog/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/picture/avatar.jpg">
      <meta itemprop="name" content="Ryan Shu">
      <meta itemprop="description" content="全栈 | 硬件 | 篮球 | 游戏">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Sapphire">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2019/10/19/first-blog/" class="post-title-link" itemprop="url">平平淡淡的一天</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-10-19 18:19:11" itemprop="dateCreated datePublished" datetime="2019-10-19T18:19:11+08:00">2019-10-19</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E6%91%B8%E9%B1%BC%E9%9A%8F%E7%AC%94/" itemprop="url" rel="index"><span itemprop="name">摸鱼随笔</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>30</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="我的一天："><a href="#我的一天：" class="headerlink" title="我的一天：  "></a>我的一天：  </h1><hr>
<p>上午：改bug  </p>
<hr>
<p>下午：<del><strong>摸摸鱼</strong></del> 远程学习</p>
<hr>
<p>晚上：打FF14  </p>
<hr>
<p><img data-src="/picture/first.jpg" alt="avatar"></p>
<hr>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/3/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/3/">3</a><span class="page-number current">4</span>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Ryan Shu"
      src="/picture/avatar.jpg">
  <p class="site-author-name" itemprop="name">Ryan Shu</p>
  <div class="site-description" itemprop="description">全栈 | 硬件 | 篮球 | 游戏</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">40</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">34</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">82</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/sususama5555" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sususama5555" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:876324872@qq.com" title="E-Mail → mailto:876324872@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://weibo.com/u/5330189327" title="Weibo → https:&#x2F;&#x2F;weibo.com&#x2F;u&#x2F;5330189327" rel="noopener" target="_blank"><i class="fab fa-weibo fa-fw"></i>Weibo</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://steamcommunity.com/profiles/76561198294148424/" title="steam → https:&#x2F;&#x2F;steamcommunity.com&#x2F;profiles&#x2F;76561198294148424&#x2F;" rel="noopener" target="_blank"><i class="fab fa-steam fa-fw"></i>steam</a>
      </span>
      <span class="links-of-author-item">
        <a href="/atom.xml" title="RSS → &#x2F;atom.xml"><i class="fa fa-rss fa-fw"></i>RSS</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="http://ddoudou.xyz/" title="http:&#x2F;&#x2F;ddoudou.xyz" rel="noopener" target="_blank">豆豆的博客</a>
        </li>
    </ul>
  </div>

      </div>

      <!-- 音乐播放器 -->
      
           <div>
              <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="210" height="110" src="//music.163.com/outchain/player?type=2&id=4226232&auto=1&height=66"></iframe>
           </div>
      

      <!-- 滚动条 -->
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        
  <div class="beian"><a href="https://beian.miit.gov.cn/" rel="noopener" target="_blank">粤ICP备20063016号-2 </a>
  </div>

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Ryan Shu</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">180k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">2:44</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/pjax/pjax.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/lozad@1/dist/lozad.min.js"></script>

<script src="/js/utils.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>

<script src="/js/bookmark.js"></script>

  <script>
var pjax = new Pjax({
  selectors: [
    'head title',
    '#page-configurations',
    '.content-wrap',
    '.post-toc-wrap',
    '.languages',
    '#pjax'
  ],
  switches: {
    '.post-toc-wrap': Pjax.switches.innerHTML
  },
  analytics: false,
  cacheBust: false,
  scrollTo : !CONFIG.bookmark.enable
});

window.addEventListener('pjax:success', () => {
  document.querySelectorAll('script[data-pjax], script#page-configurations, #pjax script').forEach(element => {
    var code = element.text || element.textContent || element.innerHTML || '';
    var parent = element.parentNode;
    parent.removeChild(element);
    var script = document.createElement('script');
    if (element.id) {
      script.id = element.id;
    }
    if (element.className) {
      script.className = element.className;
    }
    if (element.type) {
      script.type = element.type;
    }
    if (element.src) {
      script.src = element.src;
      // Force synchronous loading of peripheral JS.
      script.async = false;
    }
    if (element.dataset.pjax !== undefined) {
      script.dataset.pjax = '';
    }
    if (code !== '') {
      script.appendChild(document.createTextNode(code));
    }
    parent.appendChild(script);
  });
  NexT.boot.refresh();
  // Define Motion Sequence & Bootstrap Motion.
  if (CONFIG.motion.enable) {
    NexT.motion.integrator
      .init()
      .add(NexT.motion.middleWares.subMenu)
      .add(NexT.motion.middleWares.postList)
      .bootstrap();
  }
  NexT.utils.updateSidebarPosition();
});
</script>




  
  <script data-pjax>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="/js/local-search.js"></script>













    <div id="pjax">
  

  

    </div>
</body>
</html>
